/*
 * Copyright 2010 - 2011, The PLDesktop Development Team
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */

#ifndef PLIOPORT_H
#define PLIOPORT_H

#include <stddef.h>

#include <machine/pc/iobase.h>
#include <machine/pc/processor/processor.h>

/**
 * Handle a IO port.
 */
class PLIOPort : public PLIOBase {
public:
	/**
	 * Constructor.
	 *
	 * @param name The name of the IO port handler.
	 */
	PLIOPort(const char *name);
	/**
	 * The destructor frees the allocated ressources.
	 */
	inline virtual ~PLIOPort();
	/**
	 * Get the size of the I/O region in bytes
	 *
	 * @return The size.
	 */
	inline size_t size() const;
	/**
	 * Check whether this class is usable.
	 *
	 * @return true, if the class holds a ressource that is correctly allocated and usable.
	 */
	inline operator bool() const;
	/**
	 * Get the name of the I/O port range.
	 *
	 * @return pointer to the name of the I/O port range.
	 */
	inline const char *name() const;
	/**
	 * Free an I/O port range.
	 */
	void free();
	/**
	 * Allocate an I/O port range.
	 *
	 * @param ioPort the base I/O port.
	 * @param size the number of successive I/O ports - 1.
	 * @return true, if successfull, false otherwise.
	 */
	bool allocate(uint32_t ioPort, size_t size);
	/**
	 * Read a byte (8bit) from the I/O Port or the memory-mapped I/O region.
	 *
	 * @param offset offset from the I/O base port or the I/O base memory address.
	 * @return the byte (8bit) that have been read.
	 */
	inline uint8_t read8(size_t offset = 0);
	/**
	 * Read two byte (16bit) from the I/O Port or the memory-mapped I/O region.
	 *
	 * @param offset offset from the I/O base port or the I/O base memory address.
	 * @return the two byte (16bit) that have been read.
	 */
	inline uint16_t read16(size_t offset = 0);
	/**
	 * Read four byte (32bit) from the I/O Port or the memory-mapped I/O region.
	 *
	 * @param offset offset from the I/O base port or the I/O base memory address.
	 * @return the four byte (32bit) that have been read.
	 */
	inline uint32_t read32(size_t offset = 0);
	/**
	 * Write a byte (8bit) to the I/O port or the memory-mapped I/O region.
	 *
	 * @param value the value that should be written.
	 * @param offset offset from the I/O base port or the I/O base memory address.
	 */
	inline void write8(uint8_t value, size_t offset = 0);
	/**
	 * Write two byte (16bit) to the I/O port or the memory-mapped I/O region.
	 *
	 * @param value the value that should be written.
	 * @param offset offset from the I/O base port or the I/O base memory address.
	 */
	inline void write16(uint16_t value, size_t offset = 0);
	/**
	 * Write four byte (32bit) to the I/O port or the memory-mapped I/O region.
	 *
	 * @param value the value that should be written.
	 * @param offset offset from the I/O base port or the I/O base memory address.
	 */
	inline void write32(uint32_t value, size_t offset = 0);
private:
	PLIOPort(const PLIOPort &);
	PLIOPort &operator = (const PLIOPort &);
	// The base I/O port
	uint32_t m_ioPort;
	// The number of successive I/O ports - 1
	size_t m_size;
	// User-visible name of this I/O port range
	const char *m_name;
};

PLIOPort::~PLIOPort() {
	free();
}

size_t PLIOPort::size() const {
	return m_size;
}

PLIOPort::operator bool() const {
	return (m_size != 0);
}

const char *PLIOPort::name() const {
	return m_name;
}

uint8_t PLIOPort::read8(size_t offset) {
	return PLProcessor::instance().in8(m_ioPort + offset);
}

uint16_t PLIOPort::read16(size_t offset) {
	return PLProcessor::instance().in16(m_ioPort + offset);
}

uint32_t PLIOPort::read32(size_t offset) {
	return PLProcessor::instance().in32(m_ioPort + offset);
}

void PLIOPort::write8(uint8_t value, size_t offset) {
	PLProcessor::instance().out8(value, m_ioPort + offset);
}

void PLIOPort::write16(uint16_t value, size_t offset) {
	PLProcessor::instance().out16(value, m_ioPort + offset);
}

void PLIOPort::write32(uint32_t value, size_t offset) {
	PLProcessor::instance().out32(value, m_ioPort + offset);
}

#endif
